package per.poker.chudadi;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.BiMap;
import cn.hutool.core.math.MathUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author ：yunjia
 * @date ：2023/11/17 14:35
 * @description：
 * @modified By：
 * @version: 1.0
 */
@Slf4j
public class CardValidator {

    public static int isBigger(String card1, String card2) {
        return compareCard(card1, card2);
    }

    /**
     * @param card1
     * @param card2
     * @return int 1大于 -1小于 0错误的牌
     * @author yunjia
     * @date 2023/11/17 15:07
     */
    public static int isBigger(List<String> card1, List<String> card2) {

        if (card1.isEmpty() || card2.isEmpty() || card1.size() != card2.size()) {
            return 0;
        }
        if (card1.size() == 1) {
            return isBigger(card1.get(0), card2.get(0));
        }
        if (card1.size() <= 4) {
            if (!isPair(card1) && !isTriple(card1) && !isQuadruple(card1)) {
                return 0;
            }
            return isBigger(getMainCard(card1), getMainCard(card2));
        } else {

            CardTypeEnum type1 = fiveCards(card1);
            if (type1 == null) {
                return 0;
            }
            CardTypeEnum type2 = fiveCards(card2);
            if (type1 == type2) {
                return isBigger(getMainCard(card1), getMainCard(card2));
            } else {
                return Integer.compare(type1.getCode(), type2.getCode());
            }
        }

    }

    private static CardTypeEnum fiveCards(List<String> cards) {
        if (isFlush(cards)) {
            return CardTypeEnum.FLUSH;
        }
        if (is3N2(cards)) {
            return CardTypeEnum.THREE_WITH_TWO;
        }
        if (is4N1(cards)) {
            return CardTypeEnum.FOURTH_WITH_ONE;
        }
        if (isStraight(cards)) {
            return CardTypeEnum.STRAIGHT;
        }
        return null;
    }

    public static String getMainCard(List<String> cards) {

        if (cards.size() == 1) {
            return cards.get(0);
        }
        if (isPair(cards)) {
            cards.sort(CardValidator::compareCard);
            return cards.get(1);
        }
        if (isTriple(cards)) {
            return cards.get(0);
        }
        if (isQuadruple(cards)) {
            return cards.get(0);
        }
        if (isFlush(cards)) {
            cards.sort(CardValidator::compareCard);
            return cards.get(4);
        }
        if (is3N2(cards)) {
            Map<String, Integer> map = new HashMap<>();
            for (String card : cards) {
                map.put(card.substring(1), map.getOrDefault(card.substring(1), 0) + 1);
            }
            BiMap<String, Integer> biMap = new BiMap<>(map);
            String cardNum = biMap.getInverse().get(3);
            return "♠" + cardNum;
        }
        if (is4N1(cards)) {
            Map<String, Integer> map = new HashMap<>();
            for (String card : cards) {
                map.put(card.substring(1), map.getOrDefault(card.substring(1), 0) + 1);
            }
            BiMap<String, Integer> biMap = new BiMap<>(map);
            String cardNum = biMap.getInverse().get(4);
            return "♠" + cardNum;
        }
        if (isStraight(cards)) {
            cards.sort(CardValidator::compareCard);
            return cards.get(4);
        }
        return null;

    }

    private static int compareCard(String card1, String card2) {
        CardEnum cardEnum1 = EnumUtil.getBy(CardEnum.class, e -> ObjectUtil.equal(card1.substring(1), e.getCode()));
        CardEnum cardEnum2 = EnumUtil.getBy(CardEnum.class, e -> ObjectUtil.equal(card2.substring(1), e.getCode()));

        TypeEnum color1 = EnumUtil.getBy(TypeEnum.class, e -> ObjectUtil.equal(card1.substring(0, 1), e.getCode()));
        TypeEnum color2 = EnumUtil.getBy(TypeEnum.class, e -> ObjectUtil.equal(card2.substring(0, 1), e.getCode()));

        if (color1 == color2 && cardEnum1 != cardEnum2) {
            return Integer.compare(cardEnum1.getNum(), cardEnum2.getNum());
        } else if (color1 != color2 && cardEnum1 == cardEnum2) {
            return Integer.compare(color1.getNum(), color2.getNum());
        } else if (color1 != color2) {
            return Integer.compare(cardEnum1.getNum(), cardEnum2.getNum());
        } else {
            return 0;
        }

    }

    static boolean isPair(List<String> cards) {
        if (cards.size() != CardTypeEnum.PAIR.getLen()) {
            return false;
        }
        String card1 = cards.get(0);
        String card2 = cards.get(1);

        String cardNum1 = card1.substring(1);
        String cardNum2 = card2.substring(1);

        return ObjectUtil.equal(cardNum1, cardNum2);
    }

    static boolean isTriple(List<String> cards) {
        if (cards.size() != CardTypeEnum.TRIPLE.getLen()) {
            return false;
        }
        String card1 = cards.get(0);
        String card2 = cards.get(1);
        String card3 = cards.get(2);

        String cardNum1 = card1.substring(1);
        String cardNum2 = card2.substring(1);
        String cardNum3 = card3.substring(1);

        return ObjectUtil.equal(cardNum1, cardNum2) && ObjectUtil.equal(cardNum2, cardNum3);
    }

    static boolean isQuadruple(List<String> cards) {
        if (cards.size() != CardTypeEnum.QUADRUPLE.getLen()) {
            return false;
        }
        String card1 = cards.get(0);
        String card2 = cards.get(1);
        String card3 = cards.get(2);
        String card4 = cards.get(3);

        String cardNum1 = card1.substring(1);
        String cardNum2 = card2.substring(1);
        String cardNum3 = card3.substring(1);
        String cardNum4 = card4.substring(1);

        return ObjectUtil.equal(cardNum1, cardNum2) && ObjectUtil.equal(cardNum2, cardNum3) && ObjectUtil.equal(cardNum3, cardNum4);
    }

    static boolean isFlush(List<String> cards) {
        if (cards.size() != CardTypeEnum.FLUSH.getLen()) {
            return false;
        }

        cards.sort((o1, o2) -> {
            CardEnum cardEnum1 = EnumUtil.getBy(CardEnum.class, e -> ObjectUtil.equal(o1.substring(1), e.getCode()));
            CardEnum cardEnum2 = EnumUtil.getBy(CardEnum.class, e -> ObjectUtil.equal(o2.substring(1), e.getCode()));
            return Integer.compare(cardEnum1.getNum(), cardEnum2.getNum());
        });

        String card5 = cards.get(4);
        CardEnum cardEnum5 = EnumUtil.getBy(CardEnum.class, e -> ObjectUtil.equal(card5.substring(1), e.getCode()));

        if (cardEnum5 == CardEnum._2 || cardEnum5 == CardEnum._3) {
            return false;
        }
        for (int i = 1; i < cards.size(); i++) {
            int finalI = i;
            CardEnum later = EnumUtil.getBy(CardEnum.class, e -> ObjectUtil.equal(cards.get(finalI).substring(1), e.getCode()));
            CardEnum former = EnumUtil.getBy(CardEnum.class, e -> ObjectUtil.equal(cards.get(finalI - 1).substring(1), e.getCode()));
            if (former.getNum() + 1 != later.getNum()) {
                return false;
            }
        }
        return true;
    }

    static boolean is3N2(List<String> cards) {
        if (cards.size() != CardTypeEnum.THREE_WITH_TWO.getLen()) {
            return false;
        }
        Map<String, Integer> map = new HashMap<>(4);
        for (String card : cards) {
            map.put(card.substring(1), map.getOrDefault(card.substring(1), 0) + 1);
        }
        return CollUtil.containsAll(map.values(), CollUtil.newArrayList(2, 3));

    }

    static boolean is4N1(List<String> cards) {
        if (cards.size() != CardTypeEnum.FOURTH_WITH_ONE.getLen()) {
            return false;
        }

        Map<String, Integer> map = new HashMap<>(4);
        for (String card : cards) {
            map.put(card.substring(1), map.getOrDefault(card.substring(1), 0) + 1);
        }
        return CollUtil.containsAll(map.values(), CollUtil.newArrayList(1, 4));
    }

    static boolean isStraight(List<String> cards) {
        return isFlush(cards) &&
                cards.stream().allMatch(c -> ObjectUtil.equal(c.substring(0, 1), cards.get(0).substring(0, 1)));
    }

    public static void main(String[] args) {
//        System.out.println(isBigger(CollUtil.newArrayList("♣6", "♦6", "♠6", "♥6", "♥4"),
//                CollUtil.newArrayList("♣5", "♦5", "♠5", "♠7", "♥7")));
        //System.out.println(getMainCard(CollUtil.newArrayList("♣6", "♦6")));

        List<String> list = CollUtil.newArrayList("♣10", "♥J", "♠Q", "♦9", "♥8", "♠5", "♥A", "♠10", "♣7", "♥6", "♣J", "♣4", "♣9");
        for (String[] s : MathUtil.combinationSelect(ArrayUtil.toArray(list, String.class), 5)) {
            if (isFlush(CollUtil.toList(s))) {
                System.out.println(CollUtil.toList(s));
            }
        }

        //System.out.println(isFlush(CollUtil.newArrayList("♣10", "♥J", "♠Q", "♥A", "♠10")));
    }
}
